/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package plp1;

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 *
 * @author eltorre
 */
public class ALexico{

	private int fila; //fila
	private int columna; //columna

	private String actual;
	private String cola;

	private RandomAccessFile fichero;

	public ALexico(String path)
	{
		fila = 1;
		columna = 0;
		cola ="";
		try
		{
			fichero = new RandomAccessFile(path, "r");
		}
		catch (FileNotFoundException ex)
		{
			System.err.println("Error. El fichero no existe");
		}

	}


	private char nextChar() throws IOException
	{
		byte b;
		char c;
		if (cola.isEmpty())
		{
			b = fichero.readByte();
			c = (char)b;
		}
		else
		{
			c = cola.charAt(0);
			cola = cola.substring(1);	
		}
		return c;
	}

	public MyToken nextToken() throws Excepcion
	{
		char c = ' ', aux;

		int f = fila;
		int k = columna;

		boolean leidoNumero = false;
		boolean leidoPunto = false;
		
		actual ="";

		try
		{
			c = nextChar();
			columna ++;
			if (c == -1)
			{
				return new MyToken(MyToken.EOF);
			}

			//Eliminamos vacios delante
			while (c == '\n' || c ==' ' || c == '\t')
			{
				//System.out.print(c);
				if (c == '\n')
				{
					columna = 1;
					fila ++;
				}
				else
				{
					columna++;
				}
				c = nextChar();
			}

			f = fila;
			k = columna;
			
			//System.out.println("\n Tomanos " + c);
			switch (c)
			{
				case '(':
					return new MyToken(MyToken.PARI, f, k );
				case ')':
					return new MyToken(MyToken.PARD, f, k );
				case ';' :
					return new MyToken(MyToken.PYC, f, k );
				case '=':
					return new MyToken(MyToken.ASIG, f, k );
				case '{':
					return new MyToken(MyToken.LLAVEI, f, k );
				case '}':
					return new MyToken(MyToken.LLAVED, f, k );
			}

			if (c >= '0' && c <= '9')
			{
				leidoPunto = false;
				while (c >= '0' && c <= '9' || c == '.')
				{
					actual += c;
					if (c != '.')
					{
						leidoNumero = true;
					}
					else
					{
						if (leidoPunto == false)
						{
							leidoNumero = false;
							leidoPunto = true;
						}
						else
						{
							throw (new Excepcion("Error 1 (" + fila + "," + (columna-1) + "): caracter '.' incorrecto"));
						}
					}
					columna ++;
					c = nextChar();
				}

				if (!leidoNumero)
				{
					cola += ".";
					actual = actual.substring(0, actual.length()-1);
					columna--;
				}

				if (c != ' ' || c != '\t' || c != '\n')
				{
					columna --;
					cola += c;
				}

				try
				{
					Integer.parseInt(actual);
				}
				catch(NumberFormatException exInt)
				{
					try
					{
						Double.parseDouble(actual);
					}
					catch(NumberFormatException exDouble)
					{
						throw (new Excepcion("Error 1 (" + fila + "," + columna + "): caracter '" + actual.charAt(actual.length()-1) + "' incorrecto"));
					}
					return new MyToken(actual, MyToken.REAL, f, k );
				}
				return new MyToken(actual, MyToken.ENTERO, f, k );
			}
			
			if (c == '/')
			{
				actual += c;

				c = nextChar();
				if (c != '*')
				{
					throw new Excepcion("Error 1 (" + fila + "," + columna + "): caracter '" + actual.charAt(actual.length()-1) + "' incorrecto");
				}
				actual += c;
				columna++;

				while (actual.length() < 4 || !(actual.charAt(actual.length()-2)=='*' && actual.charAt(actual.length()-1)=='/'))
				{
					c = nextChar();

					if (c == '\n')
					{
						columna = 0;
						fila ++;
					}
					else
					{
						columna++;
					}

					actual += c;
				}
				//return new Token(actual, Token.COMENTARIO, fila, columna );
				f = fila;
				k = columna;
				return nextToken();
			}

			if (!((c>='a' && c<='z') || (c>='A' && c<='Z')|| (c>='0' && c<='9')))
			{
				throw new Excepcion("Error 1 (" + fila + "," + columna +
						"): caracter '" + c + "' incorrecto");
			}

			while (c != ' ' && c != '\t' && c != '\n' && c != '(' && c!= ')' && c != '=' 
					&& c!='{' && c!='}' && c!= ';' && c!='/' && c!='*'
					&& ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')))
			{
				actual += c;
				columna ++;

				c = nextChar();
			}

			cola += c;
			columna --;

			//System.out.println(cola + " " + Token.Tipos[Token.CLASS]);

			if ( actual.equals(MyToken.Tipos[MyToken.CLASS]) )
				return new MyToken(MyToken.CLASS, f, k );
			if ( actual.equals(MyToken.Tipos[MyToken.DOUBLE]) )
				return new MyToken(MyToken.DOUBLE, f, k );
			if ( actual.equals(MyToken.Tipos[MyToken.INT]) )
				return new MyToken(MyToken.INT, f, k );
			if ( actual.equals(MyToken.Tipos[MyToken.MAIN]) )
				return new MyToken(MyToken.MAIN, f, k );
			if ( actual.equals(MyToken.Tipos[MyToken.VOID]) )
				return new MyToken(MyToken.VOID, f, k );

			return new MyToken(actual, MyToken.ID, f, k );
		}
		catch (EOFException ex)
		{

			if (actual.equals(""))
			{
				return new MyToken(actual, MyToken.EOF, f, k);
			}
			else
			{
				if (actual.equals(("/")))
				{
					throw new Excepcion("Error 1 (" + fila + "," + columna +
						"): caracter '/' incorrecto");
				}
				if (actual.charAt(0) == '/')
				{
					if (actual.length() > 2 && actual.charAt(1) == '*'
						&& actual.charAt(actual.length()-2) == '*' && actual.charAt(actual.length()-1)=='/')
					{
						return nextToken();
					}
					throw new Excepcion ("Error 2: fin de fichero inesperado");
				}
				if (actual.charAt(0) >= '0' && actual.charAt(0)<= '9')
				{

				if (actual.charAt(actual.length()-1) == '.')
				{
					throw new Excepcion("Error 1 (" + fila + "," + (columna-1) +
						"): caracter '.' incorrecto");
				}

				try
				{
					Integer.parseInt(actual);
				}
				catch(NumberFormatException exInt)
				{
					try
					{
						Double.parseDouble(actual);
					}
					catch(NumberFormatException exDouble)
					{
						throw (new Excepcion("Error 1 (" + fila + "," + columna + "): caracter '" + actual.charAt(actual.length()-1) + "' incorrecto"));
					}
					return new MyToken(actual, MyToken.REAL, f, k );
				}
				return new MyToken(actual, MyToken.ENTERO, f, k );
				}
				if ( actual.equals(MyToken.Tipos[MyToken.CLASS]) )
					return new MyToken(MyToken.CLASS, f, k );
				if ( actual.equals(MyToken.Tipos[MyToken.DOUBLE]) )
					return new MyToken(MyToken.DOUBLE, f, k );
				if ( actual.equals(MyToken.Tipos[MyToken.INT]) )
					return new MyToken(MyToken.INT, f, k );
				if ( actual.equals(MyToken.Tipos[MyToken.MAIN]) )
					return new MyToken(MyToken.MAIN, f, k );
				if ( actual.equals(MyToken.Tipos[MyToken.VOID]) )
					return new MyToken(MyToken.VOID, f, k );

				return new MyToken(actual, MyToken.ID, f, k );
			}
			//throw (newExcepcion("Error (" + fila + " , " + columna + "): caracter " + actual.charAt(actual.length()-1) + "  incorrecto"));
		}
		catch (IOException ex)
		{
			throw new Excepcion("Fallo de entrada/Salida");
		}
	}



}
